package com.sunday.common.netty.e3_Pojo.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class TimeClient {

    public static final String SERVER_HOST = "localhost";
    public static final int SERVER_PORT = 8811;

    public static void main(String[] args) throws Exception {

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            /**
             * 常用的 Channel 实现类
             * AbstractChannel 是整个家族的基类，派生出 AbstractNioChannel、AbstractOioChannel、AbstractEpollChannel 等子类，每一种都代表了不同的 I/O 模型和协议类型。
             * 常用的 Channel 实现类有：
             *
             * NioServerSocketChannel 异步 TCP 服务端, 最常用的Server Channel。
             * NioSocketChannel 异步 TCP 客户端。最常用的Client Channel。
             * NioDatagramChannel 异步 UDP 连接。
             * OioServerSocketChannel 同步 TCP 服务端。 @Deprecated
             * OioSocketChannel 同步 TCP 客户端。@Deprecated
             * OioDatagramChannel 同步 UDP 连接。@Deprecated
             *
             * Channel的生命周期
             *
             * Channel 会有多种状态，如连接建立、连接注册、数据读写、连接销毁等。随着状态的变化，Channel 处于不同的生命周期，如下图。每一种状态都会绑定相应的事件回调
             * Channel 最常见的状态所对应的事件回调如下：
             * 事件	说明
             * channelRegistered	    Channel 创建后被注册到 EventLoop 上
             * channelUnregistered	    Channel 创建后未注册或者从 EventLoop 取消注册
             * channelActive	        Channel 处于就绪状态，可以被读写
             * channelInactive	        Channel 处于非就绪状态
             * channelRead	            Channel 可以从远端读取到数据
             * channelReadComplete	    Channel 读取数据完成
             *
             *
             */
            b.channel(NioSocketChannel.class);
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new TimeDecoder(), new TimeClientHandler());
                }
            });
            // Start the client.
            ChannelFuture f = b.connect(SERVER_HOST, SERVER_PORT).sync();
            // Wait until the connection is closed.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }

}
